Binder 中的 Parcel 数据结构分析(Java)

8/22/2023

Parcel 是一个横跨 Java 层与 Native 层的数据结构,扮演了 Binder 远程过程调用中数据传输载体的角色。客户端将数据写入 Parcel,服务端从 Parcel 中读出数据。接下来我们就从 Java 源码的角度来看看 Parcel 内部的实现原理。

Parcel 支持读写的数据类型如下:

  • Primitives:基本数据类型
  • Primitives Arrays:基本数据类型数组
  • Parcelables:实现了 Parcelable 接口的数据类型
  • Bundle 数据类型:Java 层封装的数据包,仅 Java 层支持
  • Active Objects:IBinder 对象和 FileDescriptor 对象
  • Untyped Containers:未指定泛型类型的 List Map SparseArray

Java 层的 Parcel 实际上只是一层对外提供接口的马甲,其内部核心实现都是通过 JNI 调用 Native 层的 Parcel。

# Java 层 Parcel 的初始化

在 Java 层,使用 obtain 方法来获取一个 Parcel 对象:

Parcel mParcel = Parcel.obtain()
1

obtain 的具体实现如下:

// frameworks/base/core/java/android/os/Parcel.java
//缓存池
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];

@NonNull
public static Parcel obtain() {
    final Parcel[] pool = sOwnedPool;
    synchronized (pool) {
        Parcel p;
        //从缓存池里找一个 Parcel 对象返回
        for (int i=0; i<POOL_SIZE; i++) {
            p = pool[i];
            if (p != null) {
                //这里只是将对象的引用置为空,不是将对象本身置空
                //引用置空,表示这个对象已被使用,下次 obtain 的时候就直接跳过
                pool[i] = null;
                if (DEBUG_RECYCLE) {
                    p.mStack = new RuntimeException();
                }
                p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
                return p;
            }
        }
    }
    //缓存池里的对象都被使用了,就重新 new 一个
    return new Parcel(0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

接下来我们来看看 Parcel 的构造函数:

// frameworks/base/core/java/android/os/Parcel.java
private Parcel(long nativePtr) {
    if (DEBUG_RECYCLE) {
        mStack = new RuntimeException();
    }
    //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);
    init(nativePtr);
}

//接着调用 init
private void init(long nativePtr) {
    if (nativePtr != 0) {
        mNativePtr = nativePtr;
        mOwnsNativeParcelObject = false;
    } else { // nativePtr = 0 ,走这个分支
        mNativePtr = nativeCreate();
        mOwnsNativeParcelObject = true;
    }
}

//接着调用 nativeCreate,nativeCreate 是一个 native 方法
private static native long nativeCreate();

// JNI 函数是在 Zygote 启动时注册的
// frameworks/base/core/jni/AndroidRuntime.cpp
REG_JNI(register_android_os_Parcel)

int register_android_os_Parcel(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kParcelPathName);

    gParcelOffsets.clazz = MakeGlobalRefOrDie(env, clazz);
    gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, clazz, "mNativePtr", "J");
    gParcelOffsets.obtain = GetStaticMethodIDOrDie(env, clazz, "obtain", "()Landroid/os/Parcel;");
    gParcelOffsets.recycle = GetMethodIDOrDie(env, clazz, "recycle", "()V");

    return RegisterMethodsOrDie(env, kParcelPathName, gParcelMethods, NELEM(gParcelMethods));
}

//nativeCreate 对应的 native 函数定义在 frameworks/base/core/jni/android_os_Parcel.cpp 中:

//操作很简单,就是 new 一个 Parcel,然后把地址转成 long 返回给 Java 层
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
    Parcel* parcel = new Parcel();
    return reinterpret_cast<jlong>(parcel);
}

//回到 Java 层 init 中:
private void init(long nativePtr) {
    if (nativePtr != 0) {
        mNativePtr = nativePtr;
        mOwnsNativeParcelObject = false;
    } else { // nativePtr = 0 ,走这个分支
        // Native 层返回的地址保存在 mNativePtr 成员变量中
        mNativePtr = nativeCreate();
        mOwnsNativeParcelObject = true;
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

自此,整个 Parcel 初始化过程就完成了,总结一下:

  • 我们通过调用 Parcel 类的静态方法 obtain 来获取一个 Parcel 对象
  • Parcel 中有一个缓存数组 private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];,调用 obtain 方法时,会首先从这个缓存中找一个未被使用的 Parcel 对象返回,程序中通过数组中的引用是否为空来标记 Parcel 对象是否被使用
  • 如果缓存数组中的对象都被使用了,就重新 new 一个 Parcel 返回
  • Java 层的 Parcel 是一层提供 Java 层接口的马甲,其核心功能都是通过 Native 层的 Parcel 对象实现的。在构造方法中会通过 JNI 函数 new 一个 Native 层的 Parcel 对象,并把这个对象的内存地址存放在 Java 层的 mNativePtr 成员中

# Java 层 Parcel 的回收与销毁

Java 层的 Parcel 在使用完成后,需要调用 recycle 方法来执行回收操作:

    // frameworks/base/core/java/android/os/Parcel.java
    public final void recycle() {
        if (DEBUG_RECYCLE) mStack = null;
        //调用 native 层的回收操作
        freeBuffer();

        final Parcel[] pool;
        if (mOwnsNativeParcelObject) { //在 init 中初始化为 true,走这个分支
            pool = sOwnedPool;
        } else {
            mNativePtr = 0;
            pool = sHolderPool;
        }

        //将缓存池中第一个为 null 的引用指向当前对象
        synchronized (pool) {
            for (int i=0; i<POOL_SIZE; i++) {
                if (pool[i] == null) {
                    pool[i] = this;
                    return;
                }
            }
        }
    }

    private void freeBuffer() {
        if (mOwnsNativeParcelObject) { //在 init 中初始化为 true,走这个分支
            updateNativeSize(nativeFreeBuffer(mNativePtr));
        }
        mReadWriteHelper = ReadWriteHelper.DEFAULT;
    }

    // nativeFreeBuffer 是一个 native 方法,对应的 native 函数是 android_os_Parcel_freeBuffer
    private static native long nativeFreeBuffer(long nativePtr);

    static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            parcel->freeData(); //回收内存,修改一些标记变量
            return parcel->getOpenAshmemSize();
        }
        return 0;
    }

    void Parcel::freeData()
    {
        freeDataNoInit();
        initState();
    }

    void Parcel::freeDataNoInit()
    {
        if (mOwner) {
            LOG_ALLOC("Parcel %p: freeing other owner data", this);
            //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
            mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
        } else { // mOwner 初始化为空,走这个分支
            LOG_ALLOC("Parcel %p: freeing allocated data", this);
            //清理 mObjects 数组成员指向的 flat_binder_object 对象
            releaseObjects();
            //修改一些标记变量的值
            if (mData) {
                LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity);
                pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
                if (mDataCapacity <= gParcelGlobalAllocSize) {
                gParcelGlobalAllocSize = gParcelGlobalAllocSize - mDataCapacity;
            } else {
                gParcelGlobalAllocSize = 0;
            }
            if (gParcelGlobalAllocCount > 0) {
              gParcelGlobalAllocCount--;
            }
            pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
            //清理 mData 指向的内存
            free(mData);
        }
         //清理 mObjects 指向的内存
        if (mObjects) free(mObjects);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

Parcel 中定义了 finalize 方法,用于在 gc 时回收对象:

    // frameworks/base/core/java/android/os/Parcel.java
    @Override
    protected void finalize() throws Throwable {
        if (DEBUG_RECYCLE) {
            if (mStack != null) {
                Log.w(TAG, "Client did not call Parcel.recycle()", mStack);
            }
        }
        // 接着调用 destroy()
        destroy();
    }

    private void destroy() {
        if (mNativePtr != 0) {
            if (mOwnsNativeParcelObject) {
                //接着调用 nativeDestroy
                nativeDestroy(mNativePtr);
                updateNativeSize(0);
            }
            mNativePtr = 0;
        }
        mReadWriteHelper = null;
    }

    // nativeDestroy 是一个本地函数
    private static native void nativeDestroy(long nativePtr);

    // nativeDestroy 对应 native 层 
    // frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_destroy 函数
    static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        //直接清除内存
        delete parcel;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# Java 层 Parcel 整型数据读写

Java 层提供了 writeInt 接口写入 Int 型数据:

    // frameworks/base/core/java/android/os/Parcel.java
    public final void writeInt(int val) {
        nativeWriteInt(mNativePtr, val);
    }
    //进一步调用到 nativeWriteInt
    private static native void nativeWriteInt(long nativePtr, int val);
    //nativeWriteInt 是一个 native 方法
    //nativeWriteInt 对应的 native 函数是
    //frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_writeInt 函数
    static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
        //实际上就是调用 Native 层的 writeInt32
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            const status_t err = parcel->writeInt32(val);
            if (err != NO_ERROR) {
                signalExceptionForError(env, clazz, err);
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

可以看出 java 层只是提供一个 writeInt 的对外接口,实际操作还是通过 native 层的 writeInt32 来完成,这部分在上文已做具体分析,具体可以参考Binder 中的 Parcel 数据结构分析(C++) (opens new window)

接下来我们来看 Java 层的 Int 数据读取操作:

    // frameworks/base/core/java/android/os/Parcel.java
    public final int readInt() {
        return nativeReadInt(mNativePtr);
    }

    //实际是调用 native 方法
    private static native int nativeReadInt(long nativePtr); 

    //对应的 native 函数
    //frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_readInt 函数
    static jint android_os_Parcel_readInt(jlong nativePtr)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            //仍然是调用 native 层的 readInt32
            return parcel->readInt32();
        }
        return 0;
    }   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

可以看出 java 层只是提供一个 readInt 的对外接口,实际操作还是通过 native 层的 readInt32 来完成,这部分在上文已做具体分析,具体可以参考Binder 中的 Parcel 数据结构分析(C++) (opens new window)

String 类型的读取和 Int 类型一样也是委托给 Native 来做具体实现,这部分内容就留给读者自己分析了。

# Java 层 Parcel IBinder 数据读写

接下来我们来看看 IBinder 类型的数据是怎么读写的:

    // frameworks/base/core/java/android/os/Parcel.java
    public final void writeStrongBinder(IBinder val) {
        nativeWriteStrongBinder(mNativePtr, val);
    }
    
    private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);

    //对应的 native 函数
    //frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_writeStrongBinder 函数
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

这里仍然是调用 native 层的 writeStrongBinder 来完成具体的读写,这部分在上文已做具体分析,具体可以参考Binder 中的 Parcel 数据结构分析(C++) (opens new window)

接下来我们把重点放在 ibinderForJavaObject,ibinderForJavaObject 的作用是把 java 层的 IBinder 转换为 Native 层的 IBinder:

在查看源码之前我们先回顾下 Binder Java 层的总体架构:

在 Java 层,服务端类是 Binder,其内部有一个 long 型数据是一个 Native 层指针,指向一个 native 层的 BBinder 对象。

在 Java 层,客户端类或者叫代理类是 BinderProxy,内部有一个 long 型数据是一个 Native 层指针,指向一个 native 层的 JavaBBinder 对象。JavaBBinder 对象内部又有指针执行一个 BBinder 对象,

接下来,我们就来看看 ibinderForJavaObject 的具体实现:

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;

    //obj 类型是 Binder,服务端类
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        //获取到 Java 层 Binder 对应的 Native 层 JavaBBinderHolder 对象
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        //返回 JavaBBinderHolder 对象内部指针指向的 BBinder 对象
        return jbh->get(env, obj);
    }

    //obj 类型是 BinderProxy,客户端类
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        //返回 Java 层 BinderProxy 对应的 Native 层 BpBinder 对象
        return getBPNativeData(env, obj)->mObject;
    }

    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

接下来我们再来看看 IBinder 的读操作:

    // frameworks/base/core/java/android/os/Parcel.java
    public final IBinder readStrongBinder() {
        return nativeReadStrongBinder(mNativePtr);
    }
    private static native IBinder nativeReadStrongBinder(long nativePtr);

//对应的 native 函数
//frameworks/base/core/jni/android_os_Parcel.cpp 中的 android_os_Parcel_readStrongBinder 函数
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

这里仍然是调用 native 层的 readStrongBinder 来完成具体的读写,这部分在上文已做具体分析,具体可以参考Binder 中的 Parcel 数据结构分析(C++) (opens new window)

接下来我们重点关注一下 javaObjectForIBinder 函数,这个函数用于将 Native 层的 IBinder 对象转换为 Java 层的 IBinder 对象:

//frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    //val 类型是 JavaBBinder
    // JavaBBinder 有一个成员变量 mObject 就是 Java 层的 Binder 对象,这里获取到直接返回
    if (val->checkSubclass(&gBinderOffsets)) {
        // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }

    //构造 BinderProxyNativeData 结构体
    BinderProxyNativeData* nativeData = new BinderProxyNativeData();
    nativeData->mOrgue = new DeathRecipientList;
    nativeData->mObject = val;

    //gBinderProxyOffsets 中保存了 BinderProxy 类相关的信息
    //调用 Java 层 GetInstance 方法获得一个 BinderProxy 对象
    jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
            gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
    if (env->ExceptionCheck()) { //异常处理
        // In the exception case, getInstance still took ownership of nativeData.
        return NULL;
    }
    //数据做一些检查修改操作
    BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
    if (actualNativeData == nativeData) {
        // Created a new Proxy
        uint32_t numProxies = gNumProxies.fetch_add(1, std::memory_order_relaxed);
        uint32_t numLastWarned = gProxiesWarned.load(std::memory_order_relaxed);
        if (numProxies >= numLastWarned + PROXY_WARN_INTERVAL) {
            // Multiple threads can get here, make sure only one of them gets to
            // update the warn counter.
            if (gProxiesWarned.compare_exchange_strong(numLastWarned,
                        numLastWarned + PROXY_WARN_INTERVAL, std::memory_order_relaxed)) {
                ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies);
            }
        }
    } else {
        delete nativeData;
    }

    //返回构建好的 BinderProxy
    return object;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 参考资料